package xiao_jin.fantastic_journey.core.common.block.relictechentity;

import com.mojang.serialization.MapCodec;
import net.minecraft.block.*;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.ItemPlacementContext;
import net.minecraft.item.ItemStack;
import net.minecraft.state.StateManager;
import net.minecraft.state.property.BooleanProperty;
import net.minecraft.state.property.Properties;
import net.minecraft.util.Hand;
import net.minecraft.util.ItemActionResult;
import net.minecraft.util.ItemScatterer;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import xiao_jin.fantastic_journey.core.common.block.entity.relictechblock.RelictechTableBlockEntity;

@SuppressWarnings("unused")
public class RelictechTableBlock extends BlockWithEntity implements BlockEntityProvider, Waterloggable {
    public static final BooleanProperty ACTIVATION = BooleanProperty.of("activation");
    public static final BooleanProperty WATERLOGGED = Properties.WATERLOGGED;

    public RelictechTableBlock(Settings settings) {
        super(settings);
        setDefaultState(getDefaultState()
                .with(ACTIVATION, false)
                .with(WATERLOGGED, false)
        );
    }

    @Override
    protected MapCodec<RelictechTableBlock> getCodec() {
        return createCodec(RelictechTableBlock::new);
    }

    @Override
    protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
        builder.add(ACTIVATION).add(Properties.WATERLOGGED);
    }

    @Override
    public FluidState getFluidState(BlockState state) {
        return state.get(WATERLOGGED) ? Fluids.WATER.getStill(false) : super.getFluidState(state);
    }

    @Nullable
    @Override
    public BlockState getPlacementState(ItemPlacementContext ctx) {
        return this.getDefaultState().with(WATERLOGGED, ctx.getWorld()
                .getFluidState(ctx.getBlockPos()).getFluid() == Fluids.WATER);
    }

    private static final VoxelShape UPPER = Block.createCuboidShape(3.0, 12.0, 3.0, 13.0, 16.0, 13.0);
    private static final VoxelShape CENTRE = Block.createCuboidShape(5.0, 4.0, 5.0, 11.0, 12.0, 11.0);
    private static final VoxelShape BELOW = Block.createCuboidShape(4.0, 0.0, 4.0, 12.0, 4.0, 12.0);
    private static final VoxelShape UNION = VoxelShapes.union(UPPER, CENTRE, BELOW);

    @Override
    public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
        return UNION;
    }

    @Override
    public BlockRenderType getRenderType(BlockState state) {
        return BlockRenderType.MODEL;
    }

    @Override
    protected ItemActionResult onUseWithItem(ItemStack stack, BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
        if (world.isClient) return ItemActionResult.success(true);
        if (!(world.getBlockEntity(pos) instanceof RelictechTableBlockEntity tile)) return ItemActionResult.FAIL;
        var isTableEmpty = tile.inventory.getStack(0).isEmpty();
        var isHandEmpty = stack.isEmpty();
        var isSameItem = tile.inventory.getStack(0).getItem() == stack.getItem();

        if (!isHandEmpty && isTableEmpty) {
            // put item to the table
            tile.inventory.setStack(0, stack.copy());
            if (!player.isCreative()) stack.split(1);
            tile.markDirty();
            return ItemActionResult.SUCCESS;
        }

        if (isHandEmpty && !isTableEmpty) {
            // get the item out to the hand(the hand is empty)
            player.setStackInHand(hand, tile.inventory.removeStack(0));
            tile.markDirty();
            return ItemActionResult.SUCCESS;
        }

        if (isSameItem && !isTableEmpty && stack.getMaxCount() >= stack.getCount() + 1) {
            // get the item out to the hand(the hand has the same item)
            if (!player.isCreative()) stack.setCount(stack.getCount() + 1);
            tile.inventory.removeStack(0);
            tile.markDirty();
            return ItemActionResult.SUCCESS;
        }

        return ItemActionResult.CONSUME;
    }

    @Override
    public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) {
        if (state.getBlock() == newState.getBlock()) return;
        if (world.getBlockEntity(pos) instanceof RelictechTableBlockEntity tile)
            ItemScatterer.spawn(world, pos, tile.inventory);

        super.onStateReplaced(state, world, pos, newState, moved);
    }

    @Override
    public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
        return new RelictechTableBlockEntity(pos, state);
    }
}